New endpoint: top chain pairs by number of transfers (#307)
### Summary Tracking issue: https://github.com/wormhole-foundation/wormhole-explorer/issues/275 This pull request implements the endpoint `GET /api/v1/top-chain-pairs-by-num-transfers`, which returns the chain pairs that have the most transfers.Internally, the endpoint uses data summarized daily to speed up query execution times. This endpoint has a mandatory query parameter named timerange, which must be set to `7d`, `15d` or `30d`.
This commit is contained in:
parent
25a675f99a
commit
c25ebcb6fc
|
@ -8,12 +8,14 @@ option task = {
|
||||||
start = date.sub(from: now(), d: 24h)
|
start = date.sub(from: now(), d: 24h)
|
||||||
stop = now()
|
stop = now()
|
||||||
|
|
||||||
from(bucket: "wormscan-24hours-mainnet-staging")
|
from(bucket: "wormscan")
|
||||||
|> range(start: start, stop: stop)
|
|> range(start: start, stop: stop)
|
||||||
|> filter(fn: (r) => r["_measurement"] == "vaa_volume")
|
|> filter(fn: (r) => r["_measurement"] == "vaa_volume")
|
||||||
|> filter(fn: (r) => r["_field"] == "volume")
|
|> filter(fn: (r) => r["_field"] == "volume")
|
||||||
|> drop(columns: ["app_id", "destination_address", "destination_chain"])
|
|> drop(columns: ["app_id", "destination_address", "destination_chain"])
|
||||||
|
|> group(columns: ["emitter_chain", "token_address", "token_chain"])
|
||||||
|> sum(column: "_value")
|
|> sum(column: "_value")
|
||||||
|> set(key: "_measurement", value: "vaa_volume_24h")
|
|> set(key: "_measurement", value: "asset_volumes_24h")
|
||||||
|
|> set(key: "_field", value: "volume")
|
||||||
|> map(fn: (r) => ({r with _time: start}))
|
|> map(fn: (r) => ({r with _time: start}))
|
||||||
|> to(bucket: "wormscan-30days-mainnet-staging")
|
|> to(bucket: "wormscan-30days")
|
|
@ -0,0 +1,21 @@
|
||||||
|
import "date"
|
||||||
|
|
||||||
|
option task = {
|
||||||
|
name: "chain pair transfers with 24-hour granularity",
|
||||||
|
every: 24h,
|
||||||
|
}
|
||||||
|
|
||||||
|
start = date.sub(from: now(), d: 24h)
|
||||||
|
stop = now()
|
||||||
|
|
||||||
|
from(bucket: "wormscan")
|
||||||
|
|> range(start: start, stop: stop)
|
||||||
|
|> filter(fn: (r) => r["_measurement"] == "vaa_volume")
|
||||||
|
|> filter(fn: (r) => r["_field"] == "volume")
|
||||||
|
|> drop(columns: ["app_id", "destination_address", "token_address", "token_chain", "_field"])
|
||||||
|
|> group(columns: ["emitter_chain", "destination_chain"])
|
||||||
|
|> count(column: "_value")
|
||||||
|
|> set(key: "_measurement", value: "chain_pair_transfers_24h")
|
||||||
|
|> set(key: "_field", value: "num_transfers")
|
||||||
|
|> map(fn: (r) => ({r with _time: start}))
|
||||||
|
|> to(bucket: "wormscan-30days")
|
112
api/docs/docs.go
112
api/docs/docs.go
|
@ -943,6 +943,64 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/top-assets-by-volume": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns a list of the (emitter_chain, asset) pairs with the most volume.",
|
||||||
|
"tags": [
|
||||||
|
"Wormscan"
|
||||||
|
],
|
||||||
|
"operationId": "get-top-assets-by-volume",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Time span, supported values: 7d, 15d, 30d.",
|
||||||
|
"name": "timeSpan",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/transactions.TopAssetsResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/top-chain-pairs-by-num-transfers": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns a list of the (emitter_chain, destination_chain) pairs with the highest number of transfers.",
|
||||||
|
"tags": [
|
||||||
|
"Wormscan"
|
||||||
|
],
|
||||||
|
"operationId": "get-top-chain-pairs-by-num-transfers",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Time span, supported values: 7d, 15d, 30d.",
|
||||||
|
"name": "timeSpan",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/transactions.TopChainPairsResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/vaas/": {
|
"/api/v1/vaas/": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns all VAAs. Output is paginated and can also be be sorted.",
|
"description": "Returns all VAAs. Output is paginated and can also be be sorted.",
|
||||||
|
@ -2301,6 +2359,20 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.AssetWithVolume": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"emitterChain": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"symbol": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"volume": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.ChainActivity": {
|
"transactions.ChainActivity": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2312,6 +2384,20 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.ChainPair": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"destinationChain": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"emitterChain": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"numberOfTransfers": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.Destination": {
|
"transactions.Destination": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2333,12 +2419,38 @@ const docTemplate = `{
|
||||||
"description": "Number of VAAs emitted in the last 24 hours (does not include Pyth messages).",
|
"description": "Number of VAAs emitted in the last 24 hours (does not include Pyth messages).",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"24h_volume": {
|
||||||
|
"description": "Volume transferred through the token bridge in the last 24 hours, in USD.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"total_tx_count": {
|
"total_tx_count": {
|
||||||
"description": "Number of VAAs emitted since the creation of the network (does not include Pyth messages)",
|
"description": "Number of VAAs emitted since the creation of the network (does not include Pyth messages)",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.TopAssetsResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"assets": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/transactions.AssetWithVolume"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transactions.TopChainPairsResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"chainPairs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/transactions.ChainPair"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.TransactionCountResult": {
|
"transactions.TransactionCountResult": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
@ -936,6 +936,64 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/top-assets-by-volume": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns a list of the (emitter_chain, asset) pairs with the most volume.",
|
||||||
|
"tags": [
|
||||||
|
"Wormscan"
|
||||||
|
],
|
||||||
|
"operationId": "get-top-assets-by-volume",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Time span, supported values: 7d, 15d, 30d.",
|
||||||
|
"name": "timeSpan",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/transactions.TopAssetsResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/top-chain-pairs-by-num-transfers": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns a list of the (emitter_chain, destination_chain) pairs with the highest number of transfers.",
|
||||||
|
"tags": [
|
||||||
|
"Wormscan"
|
||||||
|
],
|
||||||
|
"operationId": "get-top-chain-pairs-by-num-transfers",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Time span, supported values: 7d, 15d, 30d.",
|
||||||
|
"name": "timeSpan",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/transactions.TopChainPairsResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/vaas/": {
|
"/api/v1/vaas/": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns all VAAs. Output is paginated and can also be be sorted.",
|
"description": "Returns all VAAs. Output is paginated and can also be be sorted.",
|
||||||
|
@ -2294,6 +2352,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.AssetWithVolume": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"emitterChain": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"symbol": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"volume": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.ChainActivity": {
|
"transactions.ChainActivity": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2305,6 +2377,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.ChainPair": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"destinationChain": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"emitterChain": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"numberOfTransfers": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.Destination": {
|
"transactions.Destination": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2326,12 +2412,38 @@
|
||||||
"description": "Number of VAAs emitted in the last 24 hours (does not include Pyth messages).",
|
"description": "Number of VAAs emitted in the last 24 hours (does not include Pyth messages).",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"24h_volume": {
|
||||||
|
"description": "Volume transferred through the token bridge in the last 24 hours, in USD.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"total_tx_count": {
|
"total_tx_count": {
|
||||||
"description": "Number of VAAs emitted since the creation of the network (does not include Pyth messages)",
|
"description": "Number of VAAs emitted since the creation of the network (does not include Pyth messages)",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.TopAssetsResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"assets": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/transactions.AssetWithVolume"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transactions.TopChainPairsResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"chainPairs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/transactions.ChainPair"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.TransactionCountResult": {
|
"transactions.TransactionCountResult": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
@ -466,6 +466,15 @@ definitions:
|
||||||
next:
|
next:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
transactions.AssetWithVolume:
|
||||||
|
properties:
|
||||||
|
emitterChain:
|
||||||
|
$ref: '#/definitions/vaa.ChainID'
|
||||||
|
symbol:
|
||||||
|
type: string
|
||||||
|
volume:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
transactions.ChainActivity:
|
transactions.ChainActivity:
|
||||||
properties:
|
properties:
|
||||||
txs:
|
txs:
|
||||||
|
@ -473,6 +482,15 @@ definitions:
|
||||||
$ref: '#/definitions/transactions.Tx'
|
$ref: '#/definitions/transactions.Tx'
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
|
transactions.ChainPair:
|
||||||
|
properties:
|
||||||
|
destinationChain:
|
||||||
|
$ref: '#/definitions/vaa.ChainID'
|
||||||
|
emitterChain:
|
||||||
|
$ref: '#/definitions/vaa.ChainID'
|
||||||
|
numberOfTransfers:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
transactions.Destination:
|
transactions.Destination:
|
||||||
properties:
|
properties:
|
||||||
chain:
|
chain:
|
||||||
|
@ -488,11 +506,29 @@ definitions:
|
||||||
description: Number of VAAs emitted in the last 24 hours (does not include
|
description: Number of VAAs emitted in the last 24 hours (does not include
|
||||||
Pyth messages).
|
Pyth messages).
|
||||||
type: string
|
type: string
|
||||||
|
24h_volume:
|
||||||
|
description: Volume transferred through the token bridge in the last 24 hours,
|
||||||
|
in USD.
|
||||||
|
type: string
|
||||||
total_tx_count:
|
total_tx_count:
|
||||||
description: Number of VAAs emitted since the creation of the network (does
|
description: Number of VAAs emitted since the creation of the network (does
|
||||||
not include Pyth messages)
|
not include Pyth messages)
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
transactions.TopAssetsResponse:
|
||||||
|
properties:
|
||||||
|
assets:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/transactions.AssetWithVolume'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
transactions.TopChainPairsResponse:
|
||||||
|
properties:
|
||||||
|
chainPairs:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/transactions.ChainPair'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
transactions.TransactionCountResult:
|
transactions.TransactionCountResult:
|
||||||
properties:
|
properties:
|
||||||
count:
|
count:
|
||||||
|
@ -1242,6 +1278,46 @@ paths:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
tags:
|
tags:
|
||||||
- Wormscan
|
- Wormscan
|
||||||
|
/api/v1/top-assets-by-volume:
|
||||||
|
get:
|
||||||
|
description: Returns a list of the (emitter_chain, asset) pairs with the most
|
||||||
|
volume.
|
||||||
|
operationId: get-top-assets-by-volume
|
||||||
|
parameters:
|
||||||
|
- description: 'Time span, supported values: 7d, 15d, 30d.'
|
||||||
|
in: query
|
||||||
|
name: timeSpan
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/transactions.TopAssetsResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
tags:
|
||||||
|
- Wormscan
|
||||||
|
/api/v1/top-chain-pairs-by-num-transfers:
|
||||||
|
get:
|
||||||
|
description: Returns a list of the (emitter_chain, destination_chain) pairs
|
||||||
|
with the highest number of transfers.
|
||||||
|
operationId: get-top-chain-pairs-by-num-transfers
|
||||||
|
parameters:
|
||||||
|
- description: 'Time span, supported values: 7d, 15d, 30d.'
|
||||||
|
in: query
|
||||||
|
name: timeSpan
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/transactions.TopChainPairsResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
tags:
|
||||||
|
- Wormscan
|
||||||
/api/v1/vaas/:
|
/api/v1/vaas/:
|
||||||
get:
|
get:
|
||||||
description: Returns all VAAs. Output is paginated and can also be be sorted.
|
description: Returns all VAAs. Output is paginated and can also be be sorted.
|
||||||
|
|
|
@ -19,7 +19,7 @@ type Scorecards struct {
|
||||||
Volume24h string
|
Volume24h string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssetDTO is used for the return value of the function `GetTopAssetsByVolume`.
|
// AssetDTO is used for the return value of the function `GetTopAssets`.
|
||||||
type AssetDTO struct {
|
type AssetDTO struct {
|
||||||
EmitterChain sdk.ChainID
|
EmitterChain sdk.ChainID
|
||||||
TokenChain sdk.ChainID
|
TokenChain sdk.ChainID
|
||||||
|
@ -27,27 +27,34 @@ type AssetDTO struct {
|
||||||
Volume string
|
Volume string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TopAssetsTimerange is used as an input parameter for the function `GetTopAssetsByVolume`.
|
// ChainPairDTO is used for the return value of the function `GetTopChainPairs`.
|
||||||
type TopAssetsTimerange string
|
type ChainPairDTO struct {
|
||||||
|
EmitterChain sdk.ChainID
|
||||||
|
DestinationChain sdk.ChainID
|
||||||
|
NumberOfTransfers string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TopStatisticsTimeSpan is used as an input parameter for the functions `GetTopAssets` and `GetTopChainPairs`.
|
||||||
|
type TopStatisticsTimeSpan string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TopAssetsTimerange7Days TopAssetsTimerange = "7d"
|
TimeSpan7Days TopStatisticsTimeSpan = "7d"
|
||||||
TopAssetsTimerange15Days TopAssetsTimerange = "15d"
|
TimeSpan15Days TopStatisticsTimeSpan = "15d"
|
||||||
TopAssetsTimerange30Days TopAssetsTimerange = "30d"
|
TimeSpan30Days TopStatisticsTimeSpan = "30d"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewTopAssetsTimerange parses a string and returns a `TopAssetsTimerange`.
|
// ParseTopStatisticsTimeSpan parses a string and returns a `TopAssetsTimeSpan`.
|
||||||
func NewTopAssetsTimerange(s string) (*TopAssetsTimerange, error) {
|
func ParseTopStatisticsTimeSpan(s string) (*TopStatisticsTimeSpan, error) {
|
||||||
|
|
||||||
if s == string(TopAssetsTimerange7Days) ||
|
if s == string(TimeSpan7Days) ||
|
||||||
s == string(TopAssetsTimerange15Days) ||
|
s == string(TimeSpan15Days) ||
|
||||||
s == string(TopAssetsTimerange30Days) {
|
s == string(TimeSpan30Days) {
|
||||||
|
|
||||||
tmp := TopAssetsTimerange(s)
|
tmp := TopStatisticsTimeSpan(s)
|
||||||
return &tmp, nil
|
return &tmp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("invalid timerange: %s", s)
|
return nil, fmt.Errorf("invalid time span: %s", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
type GlobalTransactionDoc struct {
|
type GlobalTransactionDoc struct {
|
||||||
|
|
|
@ -61,13 +61,13 @@ from(bucket: "%s")
|
||||||
|> sum(column: "_value")
|
|> sum(column: "_value")
|
||||||
`
|
`
|
||||||
|
|
||||||
const queryTemplateTopAssetsByVolume = `
|
const queryTemplateTopAssets = `
|
||||||
import "date"
|
import "date"
|
||||||
|
|
||||||
// Get historic volumes from the summarized metric.
|
// Get historic volumes from the summarized metric.
|
||||||
summarized = from(bucket: "%s")
|
summarized = from(bucket: "%s")
|
||||||
|> range(start: -%s)
|
|> range(start: -%s)
|
||||||
|> filter(fn: (r) => r["_measurement"] == "vaa_volume_24h")
|
|> filter(fn: (r) => r["_measurement"] == "asset_volumes_24h")
|
||||||
|> group(columns: ["emitter_chain", "token_address", "token_chain"])
|
|> group(columns: ["emitter_chain", "token_address", "token_chain"])
|
||||||
|
|
||||||
// Get the current day's volume from the unsummarized metric.
|
// Get the current day's volume from the unsummarized metric.
|
||||||
|
@ -76,6 +76,7 @@ startOfDay = date.truncate(t: now(), unit: 1d)
|
||||||
raw = from(bucket: "%s")
|
raw = from(bucket: "%s")
|
||||||
|> range(start: startOfDay)
|
|> range(start: startOfDay)
|
||||||
|> filter(fn: (r) => r["_measurement"] == "vaa_volume")
|
|> filter(fn: (r) => r["_measurement"] == "vaa_volume")
|
||||||
|
|> filter(fn: (r) => r["_field"] == "volume")
|
||||||
|> group(columns: ["emitter_chain", "token_address", "token_chain"])
|
|> group(columns: ["emitter_chain", "token_address", "token_chain"])
|
||||||
|
|
||||||
// Merge all results, compute the sum, return the top 7 volumes.
|
// Merge all results, compute the sum, return the top 7 volumes.
|
||||||
|
@ -86,6 +87,36 @@ union(tables: [summarized, raw])
|
||||||
|> top(columns: ["_value"], n: 7)
|
|> top(columns: ["_value"], n: 7)
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const queryTemplateTopChainPairs = `
|
||||||
|
import "date"
|
||||||
|
|
||||||
|
// Get historic number of transfers from the summarized metric.
|
||||||
|
summarized = from(bucket: "%s")
|
||||||
|
|> range(start: -%s)
|
||||||
|
|> filter(fn: (r) => r["_measurement"] == "chain_pair_transfers_24h")
|
||||||
|
|> group(columns: ["emitter_chain", "destination_chain"])
|
||||||
|
|> sum()
|
||||||
|
|
||||||
|
// Get the current day's number of transfers from the unsummarized metric.
|
||||||
|
// This assumes that the summarization task runs exactly once per day at 00:00hs
|
||||||
|
startOfDay = date.truncate(t: now(), unit: 1d)
|
||||||
|
raw = from(bucket: "%s")
|
||||||
|
|> range(start: startOfDay)
|
||||||
|
|> filter(fn: (r) => r["_measurement"] == "vaa_volume")
|
||||||
|
|> filter(fn: (r) => r["_field"] == "volume")
|
||||||
|
|> group(columns: ["emitter_chain", "destination_chain"])
|
||||||
|
|> drop(columns: ["app_id", "destination_address", "token_address", "token_chain", "_field"])
|
||||||
|
|> group(columns: ["emitter_chain", "destination_chain"])
|
||||||
|
|> count()
|
||||||
|
|
||||||
|
// Merge all results, compute the sum, return the top 7 volumes.
|
||||||
|
union(tables: [summarized, raw])
|
||||||
|
|> group(columns: ["emitter_chain", "destination_chain"])
|
||||||
|
|> sum()
|
||||||
|
|> group()
|
||||||
|
|> top(columns: ["_value"], n: 7)
|
||||||
|
`
|
||||||
|
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
influxCli influxdb2.Client
|
influxCli influxdb2.Client
|
||||||
queryAPI api.QueryAPI
|
queryAPI api.QueryAPI
|
||||||
|
@ -121,10 +152,10 @@ func NewRepository(
|
||||||
return &r
|
return &r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) GetTopAssetsByVolume(ctx context.Context, timerange *TopAssetsTimerange) ([]AssetDTO, error) {
|
func (r *Repository) GetTopAssets(ctx context.Context, timeSpan *TopStatisticsTimeSpan) ([]AssetDTO, error) {
|
||||||
|
|
||||||
// Submit the query to InfluxDB
|
// Submit the query to InfluxDB
|
||||||
query := fmt.Sprintf(queryTemplateTopAssetsByVolume, r.bucket30DaysRetention, *timerange, r.bucket24HoursRetention)
|
query := fmt.Sprintf(queryTemplateTopAssets, r.bucket30DaysRetention, *timeSpan, r.bucketInfiniteRetention)
|
||||||
result, err := r.queryAPI.Query(ctx, query)
|
result, err := r.queryAPI.Query(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -178,6 +209,61 @@ func (r *Repository) GetTopAssetsByVolume(ctx context.Context, timerange *TopAss
|
||||||
return assets, nil
|
return assets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Repository) GetTopChainPairs(ctx context.Context, timeSpan *TopStatisticsTimeSpan) ([]ChainPairDTO, error) {
|
||||||
|
|
||||||
|
// Submit the query to InfluxDB
|
||||||
|
query := fmt.Sprintf(queryTemplateTopChainPairs, r.bucket30DaysRetention, *timeSpan, r.bucketInfiniteRetention)
|
||||||
|
result, err := r.queryAPI.Query(ctx, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if result.Err() != nil {
|
||||||
|
return nil, result.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan query results
|
||||||
|
type Row struct {
|
||||||
|
EmitterChain string `mapstructure:"emitter_chain"`
|
||||||
|
DestinationChain string `mapstructure:"destination_chain"`
|
||||||
|
NumberOfTransfers int64 `mapstructure:"_value"`
|
||||||
|
}
|
||||||
|
var rows []Row
|
||||||
|
for result.Next() {
|
||||||
|
var row Row
|
||||||
|
if err := mapstructure.Decode(result.Record().Values(), &row); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rows = append(rows, row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the rows into the response model
|
||||||
|
var assets []ChainPairDTO
|
||||||
|
for i := range rows {
|
||||||
|
|
||||||
|
// parse emitter chain
|
||||||
|
emitterChain, err := strconv.ParseUint(rows[i].EmitterChain, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to convert emitter chain field to uint16")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse destination chain
|
||||||
|
destinationChain, err := strconv.ParseUint(rows[i].DestinationChain, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to convert destination chain field to uint16")
|
||||||
|
}
|
||||||
|
|
||||||
|
// append the new item to the response
|
||||||
|
asset := ChainPairDTO{
|
||||||
|
EmitterChain: sdk.ChainID(emitterChain),
|
||||||
|
DestinationChain: sdk.ChainID(destinationChain),
|
||||||
|
NumberOfTransfers: fmt.Sprintf("%d", rows[i].NumberOfTransfers),
|
||||||
|
}
|
||||||
|
assets = append(assets, asset)
|
||||||
|
}
|
||||||
|
|
||||||
|
return assets, nil
|
||||||
|
}
|
||||||
|
|
||||||
// convertToDecimal converts an integer amount to a decimal string, with 8 decimals of precision.
|
// convertToDecimal converts an integer amount to a decimal string, with 8 decimals of precision.
|
||||||
func convertToDecimal(amount int64) string {
|
func convertToDecimal(amount int64) string {
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,12 @@ func (s *Service) GetScorecards(ctx context.Context) (*Scorecards, error) {
|
||||||
return s.repo.GetScorecards(ctx)
|
return s.repo.GetScorecards(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetTopAssetsByVolume(ctx context.Context, timerange *TopAssetsTimerange) ([]AssetDTO, error) {
|
func (s *Service) GetTopAssets(ctx context.Context, timeSpan *TopStatisticsTimeSpan) ([]AssetDTO, error) {
|
||||||
return s.repo.GetTopAssetsByVolume(ctx, timerange)
|
return s.repo.GetTopAssets(ctx, timeSpan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetTopChainPairs(ctx context.Context, timeSpan *TopStatisticsTimeSpan) ([]ChainPairDTO, error) {
|
||||||
|
return s.repo.GetTopChainPairs(ctx, timeSpan)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChainActivity get chain activity.
|
// GetChainActivity get chain activity.
|
||||||
|
|
|
@ -299,16 +299,20 @@ func ExtractIsNotional(ctx *fiber.Ctx) (bool, error) {
|
||||||
return false, response.NewInvalidQueryParamError(ctx, "INVALID <by> QUERY PARAMETER", nil)
|
return false, response.NewInvalidQueryParamError(ctx, "INVALID <by> QUERY PARAMETER", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractTopAssetsTimerange parses the `timerange` parameter from the `GET /api/v1/top-assets-by-volume` endpoint.
|
// ExtractTopStatisticsTimeSpan parses the `timespan` parameter used on top statistics endpoints.
|
||||||
func ExtractTopAssetsTimerange(ctx *fiber.Ctx) (*transactions.TopAssetsTimerange, error) {
|
//
|
||||||
|
// The endpoints that accept this parameter are:
|
||||||
|
// * `GET /api/v1/top-assets-by-volume`
|
||||||
|
// * `GET /api/v1/top-chain-pairs-by-num-transfers`
|
||||||
|
func ExtractTopStatisticsTimeSpan(ctx *fiber.Ctx) (*transactions.TopStatisticsTimeSpan, error) {
|
||||||
|
|
||||||
s := ctx.Query("timerange")
|
s := ctx.Query("timeSpan")
|
||||||
timerange, err := transactions.NewTopAssetsTimerange(s)
|
timeSpan, err := transactions.ParseTopStatisticsTimeSpan(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewInvalidQueryParamError(ctx, "INVALID <timerange> QUERY PARAMETER", nil)
|
return nil, response.NewInvalidQueryParamError(ctx, "INVALID <timeSpan> QUERY PARAMETER", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return timerange, nil
|
return timeSpan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExtractTimeRange(ctx *fiber.Ctx) (*time.Time, *time.Time, error) {
|
func ExtractTimeRange(ctx *fiber.Ctx) (*time.Time, *time.Time, error) {
|
||||||
|
|
|
@ -67,7 +67,8 @@ func RegisterRoutes(
|
||||||
api.Get("/last-txs", transactionCtrl.GetLastTransactions)
|
api.Get("/last-txs", transactionCtrl.GetLastTransactions)
|
||||||
api.Get("/scorecards", transactionCtrl.GetScorecards)
|
api.Get("/scorecards", transactionCtrl.GetScorecards)
|
||||||
api.Get("/x-chain-activity", transactionCtrl.GetChainActivity)
|
api.Get("/x-chain-activity", transactionCtrl.GetChainActivity)
|
||||||
api.Get("/top-assets-by-volume", transactionCtrl.GetTopAssetsByVolume)
|
api.Get("/top-assets-by-volume", transactionCtrl.GetTopAssets)
|
||||||
|
api.Get("/top-chain-pairs-by-num-transfers", transactionCtrl.GetTopChainPairs)
|
||||||
|
|
||||||
// vaas resource
|
// vaas resource
|
||||||
vaas := api.Group("/vaas")
|
vaas := api.Group("/vaas")
|
||||||
|
|
|
@ -85,30 +85,70 @@ func (c *Controller) GetScorecards(ctx *fiber.Ctx) error {
|
||||||
return ctx.JSON(response)
|
return ctx.JSON(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTopAssetsByVolume godoc
|
// GetTopChainPairs godoc
|
||||||
// @Description Returns the list of (emitter_chain, asset) pairs with the most volume.
|
// @Description Returns a list of the (emitter_chain, destination_chain) pairs with the highest number of transfers.
|
||||||
// @Tags Wormscan
|
// @Tags Wormscan
|
||||||
// @ID get-top-assets-by-volume
|
// @ID get-top-chain-pairs-by-num-transfers
|
||||||
// @Success 200 {object} TopAssetsByVolumeResponse
|
// @Param timeSpan query string true "Time span, supported values: 7d, 15d, 30d."
|
||||||
|
// @Success 200 {object} TopChainPairsResponse
|
||||||
// @Failure 500
|
// @Failure 500
|
||||||
// @Router /api/v1/top-assets-by-volume [get]
|
// @Router /api/v1/top-chain-pairs-by-num-transfers [get]
|
||||||
func (c *Controller) GetTopAssetsByVolume(ctx *fiber.Ctx) error {
|
func (c *Controller) GetTopChainPairs(ctx *fiber.Ctx) error {
|
||||||
|
|
||||||
// Extract query parameters
|
// Extract query parameters
|
||||||
timerange, err := middleware.ExtractTopAssetsTimerange(ctx)
|
timeSpan, err := middleware.ExtractTopStatisticsTimeSpan(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query chain pairs from the database
|
||||||
|
chainPairDTOs, err := c.srv.GetTopChainPairs(ctx.Context(), timeSpan)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error("failed to get top chain pairs by number of transfers", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert DTOs to the response model
|
||||||
|
response := TopChainPairsResponse{
|
||||||
|
ChainPairs: make([]ChainPair, 0, len(chainPairDTOs)),
|
||||||
|
}
|
||||||
|
for i := range chainPairDTOs {
|
||||||
|
chainPair := ChainPair{
|
||||||
|
EmitterChain: chainPairDTOs[i].EmitterChain,
|
||||||
|
DestinationChain: chainPairDTOs[i].DestinationChain,
|
||||||
|
NumberOfTransfers: chainPairDTOs[i].NumberOfTransfers,
|
||||||
|
}
|
||||||
|
response.ChainPairs = append(response.ChainPairs, chainPair)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.JSON(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTopAssets godoc
|
||||||
|
// @Description Returns a list of the (emitter_chain, asset) pairs with the most volume.
|
||||||
|
// @Tags Wormscan
|
||||||
|
// @ID get-top-assets-by-volume
|
||||||
|
// @Param timeSpan query string true "Time span, supported values: 7d, 15d, 30d."
|
||||||
|
// @Success 200 {object} TopAssetsResponse
|
||||||
|
// @Failure 500
|
||||||
|
// @Router /api/v1/top-assets-by-volume [get]
|
||||||
|
func (c *Controller) GetTopAssets(ctx *fiber.Ctx) error {
|
||||||
|
|
||||||
|
// Extract query parameters
|
||||||
|
timeSpan, err := middleware.ExtractTopStatisticsTimeSpan(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query assets from the database
|
// Query assets from the database
|
||||||
assetDTOs, err := c.srv.GetTopAssetsByVolume(ctx.Context(), timerange)
|
assetDTOs, err := c.srv.GetTopAssets(ctx.Context(), timeSpan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("failed to get top assets by volume", zap.Error(err))
|
c.logger.Error("failed to get top assets by volume", zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert DTOs to the response model
|
// Convert DTOs to the response model
|
||||||
response := TopAssetsByVolumeResponse{
|
response := TopAssetsResponse{
|
||||||
Assets: make([]AssetWithVolume, 0, len(assetDTOs)),
|
Assets: make([]AssetWithVolume, 0, len(assetDTOs)),
|
||||||
}
|
}
|
||||||
for i := range assetDTOs {
|
for i := range assetDTOs {
|
||||||
|
@ -133,7 +173,6 @@ func (c *Controller) GetTopAssetsByVolume(ctx *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.JSON(response)
|
return ctx.JSON(response)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChainActivity godoc
|
// GetChainActivity godoc
|
||||||
|
|
|
@ -44,13 +44,24 @@ type ScorecardsResponse struct {
|
||||||
Volume24h string `json:"24h_volume"`
|
Volume24h string `json:"24h_volume"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TopAssetsByVolumeResponse is the "200 OK" response model for `GET /api/v1/top-assets-by-volume`.
|
// TopAssetsResponse is the "200 OK" response model for `GET /api/v1/top-assets-by-volume`.
|
||||||
type TopAssetsByVolumeResponse struct {
|
type TopAssetsResponse struct {
|
||||||
Assets []AssetWithVolume `json:"assets"`
|
Assets []AssetWithVolume `json:"assets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AssetWithVolume struct {
|
type AssetWithVolume struct {
|
||||||
EmitterChain sdk.ChainID `json:"emitterChain`
|
EmitterChain sdk.ChainID `json:"emitterChain"`
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
Volume string `json:"volume"`
|
Volume string `json:"volume"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TopChainPairsResponse is the "200 OK" response model for `GET /api/v1/top-chain-pairs-by-num-transfers`.
|
||||||
|
type TopChainPairsResponse struct {
|
||||||
|
ChainPairs []ChainPair `json:"chainPairs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChainPair struct {
|
||||||
|
EmitterChain sdk.ChainID `json:"emitterChain"`
|
||||||
|
DestinationChain sdk.ChainID `json:"destinationChain"`
|
||||||
|
NumberOfTransfers string `json:"numberOfTransfers"`
|
||||||
|
}
|
||||||
|
|
|
@ -6,15 +6,18 @@ require (
|
||||||
github.com/go-redis/redis v6.15.9+incompatible
|
github.com/go-redis/redis v6.15.9+incompatible
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/sethvargo/go-envconfig v0.9.0
|
github.com/sethvargo/go-envconfig v0.9.0
|
||||||
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230417134228-3c597917f5c8
|
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230512135429-25a675f99a4b
|
||||||
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230417145436-53703d8ffcf0
|
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230426150516-e695fad0bed8
|
||||||
go.uber.org/zap v1.24.0
|
go.uber.org/zap v1.24.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
|
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/ethereum/go-ethereum v1.10.21 // indirect
|
github.com/ethereum/go-ethereum v1.10.21 // indirect
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/holiman/uint256 v1.2.1 // indirect
|
github.com/holiman/uint256 v1.2.1 // indirect
|
||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
|
|
10
jobs/go.sum
10
jobs/go.sum
|
@ -2,6 +2,8 @@ github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLj
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
|
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
|
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/davecgh/go-spew v1.1.0/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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -9,6 +11,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/ethereum/go-ethereum v1.10.21 h1:5lqsEx92ZaZzRyOqBEXux4/UR06m296RGzN3ol3teJY=
|
github.com/ethereum/go-ethereum v1.10.21 h1:5lqsEx92ZaZzRyOqBEXux4/UR06m296RGzN3ol3teJY=
|
||||||
github.com/ethereum/go-ethereum v1.10.21/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
|
github.com/ethereum/go-ethereum v1.10.21/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
@ -16,6 +20,8 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
@ -56,8 +62,12 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230417134228-3c597917f5c8 h1:nJPjdHphY0JGPorg3GrGzIf8J4YR1eyTalxT7MzPIZg=
|
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230417134228-3c597917f5c8 h1:nJPjdHphY0JGPorg3GrGzIf8J4YR1eyTalxT7MzPIZg=
|
||||||
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230417134228-3c597917f5c8/go.mod h1:wySbOH0GO2dRhkTktCCCBnZ4FgNIpy3fL4hEbNMz5KI=
|
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230417134228-3c597917f5c8/go.mod h1:wySbOH0GO2dRhkTktCCCBnZ4FgNIpy3fL4hEbNMz5KI=
|
||||||
|
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230512135429-25a675f99a4b h1:Z5ulKWN8mtUW4zX8nMl+oJeGAj0Wk2wRFLj7aDnGVoI=
|
||||||
|
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230512135429-25a675f99a4b/go.mod h1:9N5u61eWAJ5CTFu4UF6gJ8FP2FiLbU39XCRMdYKxY/I=
|
||||||
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230417145436-53703d8ffcf0 h1:uEJOLDlkpDxpShkCbFobYPd3MHZpNpkpt0+iyQnb9x4=
|
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230417145436-53703d8ffcf0 h1:uEJOLDlkpDxpShkCbFobYPd3MHZpNpkpt0+iyQnb9x4=
|
||||||
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230417145436-53703d8ffcf0/go.mod h1:dE12DOucCq23gjGGGhtbyx41FBxuHxjpPvG+ArO+8t0=
|
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230417145436-53703d8ffcf0/go.mod h1:dE12DOucCq23gjGGGhtbyx41FBxuHxjpPvG+ArO+8t0=
|
||||||
|
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230426150516-e695fad0bed8 h1:rrOyHd+H9a6Op1iUyZNCaI5v9D1syq8jDAYyX/2Q4L8=
|
||||||
|
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230426150516-e695fad0bed8/go.mod h1:dE12DOucCq23gjGGGhtbyx41FBxuHxjpPvG+ArO+8t0=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
|
Loading…
Reference in New Issue